package io.renren.modules.avanotes.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.renren.common.exception.BizCodeEnum;
import io.renren.common.exception.RRException;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.common.utils.ShiroUtils;
import io.renren.common.vo.output.ReviewScheduleOVo;
import io.renren.modules.avanotes.dao.ReviewScheduleDao;
import io.renren.modules.avanotes.entity.ReviewScheduleEntity;
import io.renren.modules.avanotes.entity.SpecialSubjectEntity;
import io.renren.modules.avanotes.entity.Supermemo2SpecialReviewEntity;
import io.renren.modules.avanotes.service.ReviewScheduleService;
import io.renren.modules.avanotes.service.SpecialSubjectService;
import io.renren.modules.avanotes.service.Supermemo2SpecialReviewService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.Map;


//@Service("reviewScheduleService")//默认只有一个实现，那就不写名称了直接使用默认的名称！
@Service
public class ReviewScheduleServiceImpl extends ServiceImpl<ReviewScheduleDao, ReviewScheduleEntity> implements ReviewScheduleService {

    @Autowired
    SpecialSubjectService specialSubjectService;

    @Autowired
    Supermemo2SpecialReviewService supermemo2SpecialReviewService;

    @Autowired
    ReviewScheduleService reviewScheduleService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<ReviewScheduleEntity> page = this.page(
                new Query<ReviewScheduleEntity>().getPage(params),
                new QueryWrapper<ReviewScheduleEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageOrderByDay(Map<String, Object> params) {
        IPage<ReviewScheduleEntity> page = this.page(
                new Query<ReviewScheduleEntity>().getPage(params),
                new QueryWrapper<ReviewScheduleEntity>().orderByAsc(ReviewScheduleEntity.CN_DAY)
        );

        IPage<ReviewScheduleOVo> convert = getReviewScheduleOVoIPage(page);
        return new PageUtils(convert);
    }


    @Override
    public PageUtils queryPageByToday(Map<String, Object> params) {
        Long userId = ShiroUtils.getUserEntity().getUserId();
        Integer today = Integer.parseInt(DateUtils.format(new Date(), DateUtils.DATE_PATTERN_INT));
        IPage<ReviewScheduleEntity> page = this.page(
                new Query<ReviewScheduleEntity>().getPage(params),
                new QueryWrapper<ReviewScheduleEntity>().eq(ReviewScheduleEntity.CN_CREATE_USER_ID, userId)
                        .eq(ReviewScheduleEntity.CN_DAY, today)
        );
        IPage<ReviewScheduleOVo> convert = getReviewScheduleOVoIPage(page);
        return new PageUtils(convert);
    }

    /**
     * 复习打卡
     *
     * @param id
     * @param q
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void attend(Long id, Integer q) {
        ReviewScheduleEntity reviewScheduleEntity = this.getById(id);
        if (reviewScheduleEntity == null) {
            throw new RRException(BizCodeEnum.ENTITY_NOT_FOUND.getMsg());
        }
        long studyId = reviewScheduleEntity.getScheduleId();
        long specialId = reviewScheduleEntity.getSpecialId();
        long userId = reviewScheduleEntity.getCreateUserId();
        //1.拿到实体类，寻找上一个 SM-2
        Supermemo2SpecialReviewEntity lastSM2ReviewEntity = supermemo2SpecialReviewService.selectLatestOneByScheduleIdAndSpecialIdAndUserId(studyId, (int) specialId, userId);
        //2.生成下一个 SM-2
        Supermemo2SpecialReviewEntity currentSM2ReviewEntity;
        if (lastSM2ReviewEntity == null || q == 0) {
            //如果为空，作为新的规则处理
            currentSM2ReviewEntity = Supermemo2SpecialReviewEntity.createFirstSM2(studyId, specialId, userId);
        } else if (lastSM2ReviewEntity.getNvalue() == 1) {
            //如果上一个是 1 那么本次就是2
            currentSM2ReviewEntity = Supermemo2SpecialReviewEntity.createSecondSM2(studyId, specialId, userId);
        } else {
            int qc = 5 - q;
            double newEF = lastSM2ReviewEntity.getCurrentEf() + (0.1 - qc * (0.08 + qc * 0.02));
            newEF = Math.max(1.3, newEF);
            int internal = (int) Math.round(lastSM2ReviewEntity.getIntervalDays() * newEF);
            currentSM2ReviewEntity = new Supermemo2SpecialReviewEntity(studyId, specialId, newEF, q, 1, lastSM2ReviewEntity.getNvalue() + 1, internal, userId);
        }
        //3.生成新的计划
        ReviewScheduleEntity nextReviewScheduleEntity = new ReviewScheduleEntity(studyId, (int) specialId, userId, reviewScheduleEntity.getDay() + currentSM2ReviewEntity.getIntervalDays());
        reviewScheduleService.save(nextReviewScheduleEntity);
        //4.更新上一个标记
        Supermemo2SpecialReviewEntity updateEntity = new Supermemo2SpecialReviewEntity();
        updateEntity.setId(lastSM2ReviewEntity.getId());
        updateEntity.setIslatest(0);
        supermemo2SpecialReviewService.updateById(updateEntity);
        //5.插入新的数据
        supermemo2SpecialReviewService.save(currentSM2ReviewEntity);
    }

    //region private

    private IPage<ReviewScheduleOVo> getReviewScheduleOVoIPage(IPage<ReviewScheduleEntity> page) {
        //进行转换
        IPage<ReviewScheduleOVo> convert = page.convert(p -> {
            ReviewScheduleOVo vo = new ReviewScheduleOVo();
            BeanUtils.copyProperties(p, vo);
            //获取专题名称
            try {
                SpecialSubjectEntity entity = specialSubjectService.getEntity(p.getSpecialId());
                vo.setSpecialSubjectName(entity.getName());
            } catch (Exception e) {
                log.error(e.getMessage());
            } finally {
                return vo;
            }
        });
        return convert;
    }
    //endregion

}